/*
 *  scalar.cpp
 *  T3nsors2
 *
 *  Created by Michael Barriault on 10-06-16.
 *  Copyright 2010 University of Guelph. All rights reserved.
 *
 */

#include "scalar.h"
#include "domain.h"
#include "others.h"
#include <iostream>
#include <cstdarg>

namespace t3 {
	
	scalar::scalar(void) {
		return;
	}
	
	scalar::~scalar(void) {
		T->clear();
		delete T;
		O->release();
		if ( id != "" )
			print((string)"Deleting " + id);
	}
	
	scalar* scalar::init(domain* O, string id) {
		scalar* S;
		try {
			S = new scalar;
			S->T = new std::vector<double>(O->size(),0.);
		}
		catch (...) {
			Alloc_Error(id);
			throw;
		}
		S->O = O;
		S->O->retain();
		S->id = id;
		S->count = 1;
		print((string)"Making new" + id);
		return S;
	}
	
	scalar* scalar::copy(scalar* c) {
		if ( this->O == c->O ) FOR(o,this->O->size()) this->at(o) = c->at(o);
		return this;
	}
	
	scalar* scalar::retain(void) {
		print(id + "Going from " + itos(count) + " to ",true);
		count++;
		print(itos(count));
		return this;
	}
	
	void scalar::release(void) {
		print(id + "Going from " + itos(count) + " to ",true);
		count--;
		print(itos(count));
		if ( count <= 0 ) delete this;
	}
	
	double& scalar::at(int i) {
		return T->at(i);
	}
	
	double& scalar::pt(int a,...) {
		va_list va;
		va_start(va,a);
		int t=0;
		FOR(i,O->N) {
			int A = (a>=0) ? a : O->at(i)+a;
			for ( int j=i-1; j>=0; j-- ) A*=O->at(j);
			t += A;
			a = va_arg(va,int);
		}
		va_end(va);
		return T->at(t);
	}


	scalar* linC(double a, scalar* x, string id) {
		scalar* y = scalar::init(x->O, id);
		FOR(o,x->O->size()) y->at(o) = a*x->at(o);
		return y;
	}

	scalar* linC(double a, scalar* x, double b, scalar* y, string id) {
		scalar* z = scalar::init(x->O, id);
		if ( x->O == y->O )
			FOR(o,x->O->size()) z->at(o) = a*x->at(o) + b*y->at(o);
		return z;
	}

	scalar* linC(double a, scalar* x, double b, scalar* y, double c, scalar* z, string id) {
		scalar* w = scalar::init(x->O, id);
		if ( x->O == y->O and y->O == z->O )
			FOR(o,x->O->size()) w->at(o) = a*x->at(o) + b*y->at(o) + c*z->at(o);
		return w;
	}
}

